/**
 * 
 */
package com.dalonedrau.jogl.engine;

import java.awt.Rectangle;

import com.dalonedrau.jogl.opengl.GameFont;
import com.dalonedrau.jogl.opengl.sprite.BasicParticleObject;
import com.dalonedrau.jogl.opengl.sprite.BasicSpriteObject;
import com.dalonedrau.jogl.opengl.sprite.FontsheetObject;
import com.dalonedrau.jogl.opengl.sprite.GroupOfImages;
import com.dalonedrau.jogl.opengl.sprite.GroupOfLines;
import com.dalonedrau.jogl.opengl.sprite.GroupOfText;
import com.dalonedrau.jogl.opengl.sprite.SpriteBase;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObjectFactory;
import com.dalonedrau.jogl.opengl.sprite.SpriteTileMap;
import com.dalonedrau.jogl.opengl.ui.GuiComponent;
import com.dalonedrau.jogl.opengl.ui.GuiComponentLibrary;
import com.dalonedrau.jogl.opengl.ui.LineOfText;
import com.dalonedrau.jogl.opengl.ui.SimpleScrollingTextWindow;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.dalonedrau.vectors.Vector3;

/**
 * @author Donald
 */
public final class Sprite {
	/** the one and only instance of the <code>Sprite</code> class. */
	private static Sprite	instance;
	/**
	 * Sprite Gives access to the singleton instance of {@link Sprite}.
	 * @return {@link Sprite}
	 */
	public static Sprite getInstance() {
		if (Sprite.instance == null) {
			Sprite.instance = new Sprite();
		}
		return Sprite.instance;
	}
	/** Hidden constructor. */
	private Sprite() {}
	/**
	 * Computes the full size of a {@link SpriteBase} instance.
	 * @param sprite the {@link SpriteBase}
	 * @throws Exception if an error occurs
	 */
	public void computeFullStats(final SpriteBase sprite) throws Exception {
		// compute colors
		float r = sprite.getRed(), g = sprite.getGreen();
		float b = sprite.getBlue(), a = sprite.getAlpha();
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_CHANGE_RED)) {
			r *= sprite.getModRed();
		}
		if (r < 0f) {
			r = 0f;
		}
		if (r > 1f) {
			r = 1f;
		}
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_CHANGE_GREEN)) {
			g *= sprite.getModGreen();
		}
		if (g < 0f) {
			g = 0f;
		}
		if (g > 1f) {
			g = 1f;
		}
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_CHANGE_BLUE)) {
			b *= sprite.getModBlue();
		}
		if (b < 0f) {
			b = 0f;
		}
		if (b > 1f) {
			b = 1f;
		}
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_CHANGE_ALPHA)) {
			a *= sprite.getModAlpha();
		}
		if (a < 0f) {
			a = 0f;
		}
		if (a > 1f) {
			a = 1f;
		}
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_DO_NOT_RENDER)) {
			a = 0;
		}
		sprite.setFullRed(r);
		sprite.setFullGreen(g);
		sprite.setFullBlue(b);
		sprite.setFullAlpha(a);
		if (sprite.isDebug()) {
			System.out.println("sprite.getFullRed()::" + sprite.getFullRed());
			System.out.println("sprite.getFullg()::" + sprite.getFullGreen());
			System.out.println("sprite.getFullb()::" + sprite.getFullBlue());
			System.out.println("sprite.getFulla()::" + sprite.getFullAlpha());
		}
		// compute size
		switch (sprite.getType()) {
		case SpriteBase.TYPE_03_GROUP_TEXT:
			GuiComponent parent =
					GuiComponentLibrary.getInstance().getComponent(
							sprite.getParentRefId());
			computeFullStatsForTextGroup(((GroupOfText) sprite), parent);
			parent = null;
			break;
		case SpriteBase.TYPE_08_TRIANGLES:
			computeFullStatsForTriangle(sprite);
			break;
		case SpriteBase.TYPE_01_GROUP_IMAGE:
			// set stats for all child images
			for (int i = 0; i < ((GroupOfImages) sprite).getNumberOfImages(); i++) {
				computeFullStats(((GroupOfImages) sprite).getImage(i));
			}
			// compute position
			if (sprite.getPosition() != null) {
				float x = (float) sprite.getPosition().getX();
				float y = (float) sprite.getPosition().getY();
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
					x += sprite.getModXl();
					y += sprite.getModYb();
				}
				sprite.setFullXl(x);
				sprite.setFullYb(y);
			}
			break;
		case SpriteBase.TYPE_09_TILE_MAP:
			// set stats for all child images
			for (int i = 0; i < ((SpriteTileMap) sprite).getNumberOfImages(); i++) {
				computeFullStats(((SpriteTileMap) sprite).getImage(i));
			}
			// set stats for all child images
			for (int i = 0; i < ((SpriteTileMap) sprite)
					.getNumberOfAnimatedImages(); i++) {
				computeFullStats(((SpriteTileMap) sprite).getAnimatedImage(i));
			}
			// compute position
			if (sprite.getPosition() != null) {
				float x = (float) sprite.getPosition().getX(), y = (float) sprite
						.getPosition().getY();
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
					x += sprite.getModXl();
					y += sprite.getModYb();
				}
				sprite.setFullXl(x);
				sprite.setFullYb(y);
			}
			break;
		case SpriteBase.TYPE_02_GROUP_LINES:
			// set stats for all child images
			for (int i = 0; i < ((GroupOfLines) sprite).getNumberOfImages(); i++) {
				computeFullStats(((GroupOfLines) sprite).getImage(i));
			}
			// compute position
			if (sprite.getPosition() != null) {
				float x = (float) sprite.getPosition().getX(), y = (float) sprite
						.getPosition().getY();
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
					x += sprite.getModXl();
					y += sprite.getModYb();
				}
				sprite.setFullXl(x);
				sprite.setFullYb(y);
			}
			break;
		case SpriteBase.TYPE_00_BASIC_IMAGE:
		case SpriteBase.TYPE_10_PARTICLE:
			computeFullStatsForImage(sprite);
			break;
		default:
			int height = sprite.getHeight();
			int width = sprite.getWidth();
			if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SIZE_CHANGED)) {
				height *= sprite.getScaleFactorHeight();
				width *= sprite.getScaleFactorWidth();
			}
			sprite.setFullHeight(height);
			sprite.setFullWidth(width);
			// compute position
			if (sprite.getPosition() != null) {
				float x = (float) sprite.getPosition().getX();
				float y = (float) sprite.getPosition().getY();
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
					x += sprite.getModXl();
					y += sprite.getModYb();
				}
				sprite.setFullXl(x);
				sprite.setFullYb(y);
			}
			break;
		}
	}
	/**
	 * Computes the full stats for a triangle.
	 * @param sprite the sprite instance
	 * @throws Exception if an error occurs
	 */
	private void computeFullStatsForTriangle(final SpriteBase sprite)
			throws Exception {
		// compute position
		if (sprite.getPosition() != null) {
			float x = (float) sprite.getPosition().getX(), y = (float) sprite
					.getPosition().getY();
			if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
				x += sprite.getModXl();
				y += sprite.getModYb();
			}
			sprite.setFullX1(sprite.getX1() + x);
			sprite.setFullY1(sprite.getY1() + y);
			sprite.setFullX2(sprite.getX2() + x);
			sprite.setFullY2(sprite.getY2() + y);
			sprite.setFullX3(sprite.getX3() + x);
			sprite.setFullY3(sprite.getY3() + y);
		}
		float xMin = sprite.getX1(),
		xMax = sprite.getX1(),
		yMin = sprite.getY1(),
		yMax = sprite.getY1();
		xMin = Math.min(xMin, sprite.getX2());
		xMin = Math.min(xMin, sprite.getX3());
		xMax = Math.max(xMax, sprite.getX2());
		xMax = Math.max(xMax, sprite.getX3());
		yMin = Math.min(yMin, sprite.getY2());
		yMin = Math.min(yMin, sprite.getY3());
		yMax = Math.max(yMax, sprite.getY2());
		yMax = Math.max(yMax, sprite.getY3());
		sprite.setHeight((int) (yMax - yMin));
		sprite.setWidth((int) (xMax - xMin));
	}
	/**
	 * Computes the full stats for an image or particle.
	 * @param sprite the sprite instance
	 * @throws Exception if an error occurs
	 */
	private void computeFullStatsForImage(final SpriteBase sprite)
			throws Exception {
		SpriteImageObject image =
				SpriteImageObjectFactory.getInstance().getImageById(
						sprite.getImageRefId());
		// 1. set texture coordinates
		sprite.setTCTop(image.getTop());
		sprite.setTCLeft(image.getLeft());
		sprite.setTCBottom(image.getBottom());
		sprite.setTCRight(image.getRight());
		// 2. set size
		int height = sprite.getHeight();
		int width = sprite.getWidth();
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SIZE_CHANGED)) {
			height *= sprite.getScaleFactorHeight();
			width *= sprite.getScaleFactorWidth();
		}
		// 3. check to see if image needs to be rendered partially
		if (sprite.getParentRefId() != -1) {
			// all sprites assigned a parent component store their position
			// relative to their parent
			GuiComponent parent =
				GuiComponentLibrary.getInstance().getComponent(
						sprite.getParentRefId());
			if (sprite.getPosition() != null
					&& parent != null
					&& parent.getPosition() != null) {
				// offset sprite's position with parent position
				float spritex = (float) sprite.getPosition().getX();
				float spritey = (float) sprite.getPosition().getY();
				float parentx = (float) parent.getPosition().getX();
				float parenty = (float) parent.getPosition().getY();
				spritex += parentx;
				spritey += parenty;
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
					spritex += sprite.getModXl();
					spritey += sprite.getModYb();
				}
				// check to see if partially rendered
				setPartiallyRendered(sprite, 
						spritey + height, // top
						spritex, // left
						spritey, // bottom
						spritex + width, // right
						parenty + parent.getPreferredSize().height,
						parentx,
						parenty,
						parentx + parent.getPreferredSize().width
						);
			}
		}
		// 4. apply modifications for partial rendering
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_RENDERED_PARTIALLY)) {
			// modifier values are applied as pixels, so need to convert
			// modifier value to a percentage of the texture's size
			float val = image.getTop();
			val += Math.abs(sprite.getModTCTop()) / image.getParentHeight();
			sprite.setFullTCTop(val);
			val = image.getLeft();
			val += Math.abs(sprite.getModTCLeft()) / image.getParentWidth();
			sprite.setFullTCLeft(val);
			val = image.getBottom();
			val -= Math.abs(sprite.getModTCBottom())
					/ image.getParentHeight();
			sprite.setFullTCBottom(val);
			val = image.getRight();
			val -= Math.abs(sprite.getModTCRight())
					/ image.getParentWidth();
			sprite.setFullTCRight(val);
		} else {
			sprite.setFullTCTop(image.getTop());
			sprite.setFullTCLeft(image.getLeft());
			sprite.setFullTCBottom(image.getBottom());
			sprite.setFullTCRight(image.getRight());
		}
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_RENDERED_PARTIALLY)) {
			height += sprite.getModHeight();
			width += sprite.getModWidth();
		}
		sprite.setFullHeight(Math.max(0, height));
		sprite.setFullWidth(Math.max(0, width));
		// 5. set the x and y values
		if (sprite.getParentRefId() != -1) {
			// all sprites assigned a parent component store their position
			// relative to their parent
			GuiComponent parent =
				GuiComponentLibrary.getInstance().getComponent(
						sprite.getParentRefId());
			if (sprite.getPosition() != null
					&& parent != null
					&& parent.getPosition() != null) {
				float x = (float) sprite.getPosition().getX();
				float y = (float) sprite.getPosition().getY();
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)
						|| sprite.hasFlag(
								SpriteBase.FLAG_SPRITE_RENDERED_PARTIALLY)) {
					x += sprite.getModXl();
					y += sprite.getModYb();
				}
				x += parent.getPosition().getX();
				y += parent.getPosition().getY();
				sprite.setFullXl(x);
				sprite.setFullYb(y);
			}
		} else {
			if (sprite.getPosition() != null) {
				float x = (float) sprite.getPosition().getX();
				float y = (float) sprite.getPosition().getY();
				if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)
						|| sprite.hasFlag(
								SpriteBase.FLAG_SPRITE_RENDERED_PARTIALLY)) {
					x += sprite.getModXl();
					y += sprite.getModYb();
				}
				sprite.setFullXl(x);
				sprite.setFullYb(y);
				if (sprite.isDebug()) {
					System.out.println("setting image's full position at "
							+ sprite.getFullXl() + "," + sprite.getFullYb() 
							+ "," + sprite.getPosition().getZ());
				}
			}
		}
	}
	/**
	 * Computes the full size of a {@link GroupOfText} instance.
	 * @param sprite the {@link GroupOfText}
	 * @param parent the parent {@link GuiComponent}
	 * @throws Exception if an error occurs
	 */
	private void computeFullStatsForTextGroup(final GroupOfText sprite,
			final GuiComponent parent) throws Exception {
		if (parent.isDebug()) {}
		if (sprite.isDebug()) {
			System.out.println("**computeFullStatsForTextGroup");
		}
		int numLines = sprite.getNumberOfLines();
		if (parent instanceof SimpleScrollingTextWindow) {
			numLines = Math
					.min(numLines,
							((SimpleScrollingTextWindow) parent)
									.getNumLinesDisplayed());
		}
		FontsheetObject font =
				GameFont.getInstance().getFontById(sprite.getFontRefId());
		int height = 0, width = 0;
		int i = 0;
		if (parent instanceof SimpleScrollingTextWindow) {
			i = ((SimpleScrollingTextWindow) parent).getCurrentLine();
			i -= numLines;
			if (i < 0) {
				i = 0;
			}
		}
		// go through each line to find the height and width
		for (; i < numLines; i++) {
			int lineHeight = 0, lineWidth = 0;
			LineOfText line = sprite.getLine(i);
			if (line.getNumberOfCharacters() > 0) {
				for (int j = 0; j < LineOfText.MAX_CHARS; j++) {
					if (line.getCharFrequency(j) > 0) {
						char c = (char) (j + GlobalConsts.INT_032);
						font.setGlyph(c);
						if (lineHeight == 0) {
							lineHeight = Math.max(font.getCharHeight(),
									lineHeight);
						}
						lineWidth += font.getCharWidth()
								* line.getCharFrequency(j);
					}
				}
			}
			height += lineHeight;
			width = Math.max(width, lineWidth);
			line = null;
		}
		if (sprite.isDebug()) {
			System.out.println("width, height::" + width + "," + height);
		}
		// TO DO - HANDLE FLAGS APPLIED TO FONT
		sprite.setFullHeight(height);
		sprite.setFullWidth(width);
		// compute position
		// the x and y position are relative to the parent's position
		if (sprite.getPosition() != null) {
			float x = (float) sprite.getPosition().getX();
			float y = (float) sprite.getPosition().getY();
			if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SHIFT_POSITION)) {
				x += sprite.getModXl();
				y += sprite.getModYb();
			}
			if (parent != null && parent.getPosition() != null) {
				x += parent.getPosition().getX();
				y += parent.getPosition().getY();
			}
			sprite.setFullXl(x);
			sprite.setFullYb(y);
			if (sprite.isDebug()) {
				System.out.println("setting text group's full position at "
						+ sprite.getFullXl() + "," + sprite.getFullYb());
			}
		}
		// reposition all lines
		if (parent instanceof SimpleScrollingTextWindow) {
			int lastLine = 0, firstLine = 0;
			lastLine = ((SimpleScrollingTextWindow) parent).getCurrentLine();
			firstLine = lastLine -
					((SimpleScrollingTextWindow) parent).getNumLinesDisplayed();
			firstLine++;
			if (firstLine < 0) {
				firstLine = 0;
			}
			float y = 0;
			for (int n = lastLine; n >= firstLine; n--) {
				// position lines
				float x = sprite.getLine(n).getXPosition();
				sprite.getLine(n).setPosition(x, y);
				y += font.getCharHeight();
				if (parent.isDebug()) {
					System.out.println(parent.getClass().getCanonicalName()
							+ " position line " + n + " at " + x + "," + y);
				}
			}
		}
		font = null;
	}
	/**
	 * Checks whether this <code>Rectangle</code> entirely contains the
	 * <code>Rectangle</code> at the specified location {@code (X,Y)} with the
	 * specified dimensions {@code (W,H)}.
	 * @param X the specified X coordinate
	 * @param Y the specified Y coordinate
	 * @param W the width of the <code>Rectangle</code>
	 * @param H the height of the <code>Rectangle</code>
	 * @return <code>true</code> if the <code>Rectangle</code> specified by
	 *         {@code (X, Y, W, H)} is entirely enclosed inside this
	 *         <code>Rectangle</code>; <code>false</code> otherwise.
	 * @since 1.1
	 */
	public boolean contains(int X, int Y, int W, int H, int x2, int y2, int w2,
			int h2) {
		if ((w2 | h2 | W | H) < 0) {
			// At least one of the dimensions is negative...
			return false;
		}
		// Note: if any dimension is zero, tests below must return false...
		if (X < x2 || Y < y2) {
			return false;
		}
		w2 += x2;
		W += X;
		if (W <= X) {
			// X+W overflowed or W was zero, return false if...
			// either original w or W was zero or
			// x+w did not overflow or
			// the overflowed x+w is smaller than the overflowed X+W
			if (w2 >= x2 || W > w2) {
				return false;
			}
		} else {
			// X+W did not overflow and W was not zero, return false if...
			// original w was zero or
			// x+w did not overflow and x+w is smaller than X+W
			if (w2 >= x2 && W > w2) {
				return false;
			}
		}
		h2 += y2;
		H += Y;
		if (H <= Y) {
			if (h2 >= y2 || H > h2) {
				return false;
			}
		} else {
			if (h2 >= y2 && H > h2) {
				return false;
			}
		}
		return true;
	}
	/**
	 * Converts a {@link SpriteBase} instance into a list of floating-point
	 * variables that define its position and color.
	 * @param sprite the {@link SpriteBase}
	 * @param array the float array list to populate
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertBasicSpriteToLineDuringRender(final SpriteBase sprite,
			final float[] array, final int offset) throws Exception {
		computeFullStats(sprite);
		float x1 = sprite.getFullXl();
		float x2 = x1 + sprite.getFullWidth();
		float y1 = sprite.getFullYb();
		float y2 = y1 + sprite.getFullHeight();
		float red = sprite.getFullRed(), green = sprite.getFullGreen();
		float blue = sprite.getFullBlue(), alpha = sprite.getFullAlpha();
		int offoff = 0;
		sprite.setFloatStoreNumber(GlobalConsts.INT_012);

		sprite.getFloatStore()[offoff] = x1;
		array[offset + offoff++] = x1;
		sprite.getFloatStore()[offoff] = y1;
		array[offset + offoff++] = y1;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		sprite.getFloatStore()[offoff] = x2;
		array[offset + offoff++] = x2;
		sprite.getFloatStore()[offoff] = y2;
		array[offset + offoff++] = y2;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;
	}
	/**
	 * Converts a {@link SpriteBase} instance into a list of floating-point
	 * variables that define its position and color.
	 * @param sprite the {@link SpriteBase}
	 * @param array the float array list to populate
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertBasicSpriteToQuadDuringRender(final SpriteBase sprite,
			final float[] array, final int offset) throws Exception {
		computeFullStats(sprite);
		float top = sprite.getFullYb() + sprite.getFullHeight();
		float left = sprite.getFullXl();
		float right = sprite.getFullXl() + sprite.getFullWidth();
		float bottom = sprite.getFullYb();
		float red = sprite.getFullRed(), green = sprite.getFullGreen();
		float blue = sprite.getFullBlue(), alpha = sprite.getFullAlpha();
		float r2 = sprite.getModRed(), g2 = sprite.getModGreen();
		float b2 = sprite.getModBlue(), a2 = sprite.getModAlpha();
		int offoff = 0;
		sprite.setFloatStoreNumber(GlobalConsts.INT_024);

		sprite.getFloatStore()[offoff] = left;
		array[offset + offoff++] = left;
		sprite.getFloatStore()[offoff] = top;
		array[offset + offoff++] = top;
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_GRADIENT_HORIZONTAL_R2L)
				|| sprite.hasFlag(
						SpriteBase.FLAG_SPRITE_GRADIENT_VERTICAL_B2T)) {
			sprite.getFloatStore()[offoff] = r2;
			array[offset + offoff++] = r2;
			sprite.getFloatStore()[offoff] = g2;
			array[offset + offoff++] = g2;
			sprite.getFloatStore()[offoff] = b2;
			array[offset + offoff++] = b2;
			sprite.getFloatStore()[offoff] = a2;
			array[offset + offoff++] = a2;
		} else {
			sprite.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			sprite.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			sprite.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			sprite.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;
		}

		sprite.getFloatStore()[offoff] = right;
		array[offset + offoff++] = right;
		sprite.getFloatStore()[offoff] = top;
		array[offset + offoff++] = top;
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_GRADIENT_HORIZONTAL_L2R)
				|| sprite.hasFlag(
						SpriteBase.FLAG_SPRITE_GRADIENT_VERTICAL_B2T)) {
			sprite.getFloatStore()[offoff] = r2;
			array[offset + offoff++] = r2;
			sprite.getFloatStore()[offoff] = g2;
			array[offset + offoff++] = g2;
			sprite.getFloatStore()[offoff] = b2;
			array[offset + offoff++] = b2;
			sprite.getFloatStore()[offoff] = a2;
			array[offset + offoff++] = a2;
		} else {
			sprite.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			sprite.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			sprite.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			sprite.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;
		}

		sprite.getFloatStore()[offoff] = right;
		array[offset + offoff++] = right;
		sprite.getFloatStore()[offoff] = bottom;
		array[offset + offoff++] = bottom;
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_GRADIENT_HORIZONTAL_L2R)
				|| sprite.hasFlag(
						SpriteBase.FLAG_SPRITE_GRADIENT_VERTICAL_T2B)) {
			sprite.getFloatStore()[offoff] = r2;
			array[offset + offoff++] = r2;
			sprite.getFloatStore()[offoff] = g2;
			array[offset + offoff++] = g2;
			sprite.getFloatStore()[offoff] = b2;
			array[offset + offoff++] = b2;
			sprite.getFloatStore()[offoff] = a2;
			array[offset + offoff++] = a2;
		} else {
			sprite.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			sprite.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			sprite.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			sprite.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;
		}

		sprite.getFloatStore()[offoff] = left;
		array[offset + offoff++] = left;
		sprite.getFloatStore()[offoff] = bottom;
		array[offset + offoff++] = bottom;
		if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_GRADIENT_HORIZONTAL_R2L)
				|| sprite.hasFlag(
						SpriteBase.FLAG_SPRITE_GRADIENT_VERTICAL_T2B)) {
			sprite.getFloatStore()[offoff] = r2;
			array[offset + offoff++] = r2;
			sprite.getFloatStore()[offoff] = g2;
			array[offset + offoff++] = g2;
			sprite.getFloatStore()[offoff] = b2;
			array[offset + offoff++] = b2;
			sprite.getFloatStore()[offoff] = a2;
			array[offset + offoff++] = a2;
		} else {
			sprite.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			sprite.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			sprite.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			sprite.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;
		}
	}
	/**
	 * Converts a {@link SpriteBase} instance into a list of floating-point
	 * variables that define its position and color.
	 * @param sprite the {@link SpriteBase}
	 * @param array the float array list to populate
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertBasicSpriteToTexturedQuadDuringRender(
			final SpriteBase sprite, final float[] array, final int offset)
			throws Exception {
		computeFullStats(sprite);
		float top = sprite.getFullYb() + sprite.getFullHeight();
		float left = sprite.getFullXl();
		float right = sprite.getFullXl() + sprite.getFullWidth();
		float bottom = sprite.getFullYb();
		float red = sprite.getFullRed(), green = sprite.getFullGreen();
		float blue = sprite.getFullBlue(), alpha = sprite.getFullAlpha();
		if (sprite.isDebug()) {
			System.out.println("red:" + red);
			System.out.println("green:" + green);
			System.out.println("blue:" + blue);
			System.out.println("alpha:" + alpha);
		}
		float tcTop = sprite.getFullTCTop();
		float tcLeft = sprite.getFullTCLeft();
		float tcBottom = sprite.getFullTCBottom();
		float tcRight = sprite.getFullTCRight();
		int offoff = 0;
		sprite.setFloatStoreNumber(GlobalConsts.INT_032);
		sprite.getFloatStore()[offoff] = left;
		array[offset + offoff++] = left;
		sprite.getFloatStore()[offoff] = top;
		array[offset + offoff++] = top;
		sprite.getFloatStore()[offoff] = tcLeft;
		array[offset + offoff++] = tcLeft;
		sprite.getFloatStore()[offoff] = tcTop;
		array[offset + offoff++] = tcTop;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		sprite.getFloatStore()[offoff] = right;
		array[offset + offoff++] = right;
		sprite.getFloatStore()[offoff] = top;
		array[offset + offoff++] = top;
		sprite.getFloatStore()[offoff] = tcRight;
		array[offset + offoff++] = tcRight;
		sprite.getFloatStore()[offoff] = tcTop;
		array[offset + offoff++] = tcTop;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		sprite.getFloatStore()[offoff] = right;
		array[offset + offoff++] = right;
		sprite.getFloatStore()[offoff] = bottom;
		array[offset + offoff++] = bottom;
		sprite.getFloatStore()[offoff] = tcRight;
		array[offset + offoff++] = tcRight;
		sprite.getFloatStore()[offoff] = tcBottom;
		array[offset + offoff++] = tcBottom;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		sprite.getFloatStore()[offoff] = left;
		array[offset + offoff++] = left;
		sprite.getFloatStore()[offoff] = bottom;
		array[offset + offoff++] = bottom;
		sprite.getFloatStore()[offoff] = tcLeft;
		array[offset + offoff++] = tcLeft;
		sprite.getFloatStore()[offoff] = tcBottom;
		array[offset + offoff++] = tcBottom;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		if (sprite.isDebug()) {
			  for (int i = 0; i < sprite.getFloatStoreNumber(); i++) {
			  System.out.print("left-top position: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("left-top texcoords: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(", ");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("left-top rgba: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("right-top position: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("right-top texcoords: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(", ");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("right-top rgba: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("right-bottom position: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("right-bottom texcoords: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(", ");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("right-bottom rgba: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("left-bottom position: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("left-bottom texcoords: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i++]);
			  System.out.print("left-bottom rgba: ");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.print(sprite.getFloatStore()[i++]);
			  System.out.print(",");
			  System.out.println(sprite.getFloatStore()[i]); }			 
		}
	}
	/**
	 * Converts a {@link SpriteBase} instance into a list of floating-point
	 * variables that define its position and color.
	 * @param sprite the {@link SpriteBase}
	 * @param array the float array list to populate
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertBasicSpriteToTriangleDuringRender(
			final SpriteBase sprite, final float[] array, final int offset)
			throws Exception {
		computeFullStats(sprite);
		float x1 = sprite.getFullX1();
		float y1 = sprite.getFullY1();
		float x2 = sprite.getFullX2();
		float y2 = sprite.getFullY2();
		float x3 = sprite.getFullX3();
		float y3 = sprite.getFullY3();
		float red = sprite.getFullRed(), green = sprite.getFullGreen(), blue = sprite
				.getFullBlue(), alpha = sprite.getFullAlpha();
		int offoff = 0;
		sprite.setFloatStoreNumber(GlobalConsts.INT_018);

		sprite.getFloatStore()[offoff] = x1;
		array[offset + offoff++] = x1;
		sprite.getFloatStore()[offoff] = y1;
		array[offset + offoff++] = y1;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		sprite.getFloatStore()[offoff] = x2;
		array[offset + offoff++] = x2;
		sprite.getFloatStore()[offoff] = y2;
		array[offset + offoff++] = y2;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		sprite.getFloatStore()[offoff] = x3;
		array[offset + offoff++] = x3;
		sprite.getFloatStore()[offoff] = y3;
		array[offset + offoff++] = y3;
		sprite.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		sprite.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		sprite.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		sprite.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;
	}
	/**
	 * Converts a {@link GroupOfImages} to a textured quad during the rendering
	 * process.
	 * @param group the {@link GroupOfImages}
	 * @param array the array used by the {@link Render} instance
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertGroupOfImagesToTexturedQuadDuringRender(
			final GroupOfImages group, final float[] array, final int offset)
			throws Exception {
		computeFullStats(group);
		int offoff = 0;
		group.setFloatStoreNumber(group.getNumberOfImages()
				* GlobalConsts.INT_032);
		for (int i = 0; i < group.getNumberOfImages(); i++) {
			float top = group.getImage(i).getFullYb()
					+ group.getImage(i).getFullHeight() + group.getFullYb();
			float left = group.getImage(i).getFullXl() + group.getFullXl();
			float right = group.getImage(i).getFullXl()
					+ group.getImage(i).getFullWidth() + group.getFullXl();
			float bottom = group.getImage(i).getFullYb() + group.getFullYb();
			float red = group.getImage(i).getFullRed(), green = group.getImage(
					i).getFullGreen(), blue = group.getImage(i).getFullBlue(), alpha = group
					.getImage(i).getFullAlpha();
			SpriteImageObject image = SpriteImageObjectFactory.getInstance()
					.getImageById(group.getImage(i).getImageRefId());
			float tcTop = image.getTop(), tcLeft = image.getLeft(), tcBottom = image
					.getBottom(), tcRight = image.getRight();

			group.getFloatStore()[offoff] = left;
			array[offset + offoff++] = left;
			group.getFloatStore()[offoff] = top;
			array[offset + offoff++] = top;
			group.getFloatStore()[offoff] = tcLeft;
			array[offset + offoff++] = tcLeft;
			group.getFloatStore()[offoff] = tcTop;
			array[offset + offoff++] = tcTop;
			group.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			group.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			group.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			group.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;

			group.getFloatStore()[offoff] = right;
			array[offset + offoff++] = right;
			group.getFloatStore()[offoff] = top;
			array[offset + offoff++] = top;
			group.getFloatStore()[offoff] = tcRight;
			array[offset + offoff++] = tcRight;
			group.getFloatStore()[offoff] = tcTop;
			array[offset + offoff++] = tcTop;
			group.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			group.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			group.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			group.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;

			group.getFloatStore()[offoff] = right;
			array[offset + offoff++] = right;
			group.getFloatStore()[offoff] = bottom;
			array[offset + offoff++] = bottom;
			group.getFloatStore()[offoff] = tcRight;
			array[offset + offoff++] = tcRight;
			group.getFloatStore()[offoff] = tcBottom;
			array[offset + offoff++] = tcBottom;
			group.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			group.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			group.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			group.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;

			group.getFloatStore()[offoff] = left;
			array[offset + offoff++] = left;
			group.getFloatStore()[offoff] = bottom;
			array[offset + offoff++] = bottom;
			group.getFloatStore()[offoff] = tcLeft;
			array[offset + offoff++] = tcLeft;
			group.getFloatStore()[offoff] = tcBottom;
			array[offset + offoff++] = tcBottom;
			group.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			group.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			group.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			group.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;
		}
	}
	/**
	 * Converts a {@link GroupOfLines} to a series of lines during the rendering
	 * process.
	 * @param group the {@link GroupOfLines}
	 * @param array the array used by the {@link Render} instance
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertGroupOfLinesToLinesDuringRender(
			final GroupOfLines group, final float[] array, final int offset)
			throws Exception {
		computeFullStats(group);
		int offoff = 0;
		group.setFloatStoreNumber(group.getNumberOfImages()
				* GlobalConsts.INT_012);
		for (int i = 0; i < group.getNumberOfImages(); i++) {
			float x1 = group.getImage(i).getFullXl() + group.getFullXl();
			float x2 = x1 + group.getImage(i).getFullWidth();
			float y1 = group.getImage(i).getFullYb() + group.getFullYb();
			float y2 = y1 + group.getImage(i).getFullHeight();
			float red = group.getImage(i).getFullRed(), green = group.getImage(
					i).getFullGreen(), blue = group.getImage(i).getFullBlue(), alpha = group
					.getImage(i).getFullAlpha();

			group.getFloatStore()[offoff] = x1;
			array[offset + offoff++] = x1;
			group.getFloatStore()[offoff] = y1;
			array[offset + offoff++] = y1;
			group.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			group.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			group.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			group.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;

			group.getFloatStore()[offoff] = x2;
			array[offset + offoff++] = x2;
			group.getFloatStore()[offoff] = y2;
			array[offset + offoff++] = y2;
			group.getFloatStore()[offoff] = red;
			array[offset + offoff++] = red;
			group.getFloatStore()[offoff] = green;
			array[offset + offoff++] = green;
			group.getFloatStore()[offoff] = blue;
			array[offset + offoff++] = blue;
			group.getFloatStore()[offoff] = alpha;
			array[offset + offoff++] = alpha;
		}
	}
	/**
	 * Converts a {@link GroupOfText} to a textured quad during the rendering
	 * process and returns the number of floating-point values used.
	 * @param lines the {@link GroupOfText}
	 * @param array the array used by the {@link Render} instance
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertGroupOfTextToTexturedQuadDuringRender(
			final GroupOfText lines, final float[] array, final int offset)
			throws Exception {
		computeFullStats(lines);
		GuiComponent parent =
				GuiComponentLibrary.getInstance().getComponent(
						lines.getParentRefId());
		if (parent instanceof SimpleScrollingTextWindow) {
			convertScrollingGroupOfTextToTexturedQuadDuringRender(
					lines, array, offset);
		} else {
			// float top = lines.getFullYb() + lines.getFullHeight();
			float left = lines.getFullXl();
			// float right = lines.getFullXl() + lines.getFullWidth();
			float bottom = lines.getFullYb();
			if (lines.isDebug()) {
				System.out.println("lines left-bottom::" + left + "," + bottom);
			}
			float red = lines.getFullRed(), green = lines.getFullGreen();
			float blue = lines.getFullBlue(), alpha = lines.getFullAlpha();
			FontsheetObject font = GameFont.getInstance().getFontById(
					lines.getFontRefId());
			int offoff = 0;
			int totalChar = 0;
			for (int i = 0; i < lines.getNumberOfLines(); i++) {
				totalChar += lines.getLine(i).getNumberOfCharacters()
						* GlobalConsts.INT_032;
			}
			lines.setFloatStoreNumber(totalChar);

			for (int curLine = 0; curLine < lines.getNumberOfLines(); curLine++) {
				LineOfText line = lines.getLine(curLine);
				for (int curChar = 0; curChar < LineOfText.MAX_CHARS; curChar++) {
					if (line.getCharFrequency(curChar) > 0) {
						font.setGlyph((char) (curChar + GlobalConsts.INT_032));
						float right = left + font.getCharWidth();
						float top = bottom + font.getCharHeight();
						float tcLeft = font.getLeft();
						float tcRight = font.getRight();
						float tcBottom = font.getBottom();
						float tcTop = font.getTop();
						for (int i = 0; i < line.getCharFrequency(curChar); i++) {
							float charY = line.getYPosition();
							float charX = line.getXPosition(curChar, i);
							if (lines.isDebug()) {
								System.out.println("char " + curChar
										+ " at x,y::" + charX + "," + charY);
							}
							lines.getFloatStore()[offoff] = left + charX;
							array[offset + offoff++] = left + charX;
							lines.getFloatStore()[offoff] = top + charY;
							array[offset + offoff++] = top + charY;
							lines.getFloatStore()[offoff] = tcLeft;
							array[offset + offoff++] = tcLeft;
							lines.getFloatStore()[offoff] = tcTop;
							array[offset + offoff++] = tcTop;
							lines.getFloatStore()[offoff] = red;
							array[offset + offoff++] = red;
							lines.getFloatStore()[offoff] = green;
							array[offset + offoff++] = green;
							lines.getFloatStore()[offoff] = blue;
							array[offset + offoff++] = blue;
							lines.getFloatStore()[offoff] = alpha;
							array[offset + offoff++] = alpha;

							lines.getFloatStore()[offoff] = right + charX;
							array[offset + offoff++] = right + charX;
							lines.getFloatStore()[offoff] = top + charY;
							array[offset + offoff++] = top + charY;
							lines.getFloatStore()[offoff] = tcRight;
							array[offset + offoff++] = tcRight;
							lines.getFloatStore()[offoff] = tcTop;
							array[offset + offoff++] = tcTop;
							lines.getFloatStore()[offoff] = red;
							array[offset + offoff++] = red;
							lines.getFloatStore()[offoff] = green;
							array[offset + offoff++] = green;
							lines.getFloatStore()[offoff] = blue;
							array[offset + offoff++] = blue;
							lines.getFloatStore()[offoff] = alpha;
							array[offset + offoff++] = alpha;

							lines.getFloatStore()[offoff] = right + charX;
							array[offset + offoff++] = right + charX;
							lines.getFloatStore()[offoff] = bottom + charY;
							array[offset + offoff++] = bottom + charY;
							lines.getFloatStore()[offoff] = tcRight;
							array[offset + offoff++] = tcRight;
							lines.getFloatStore()[offoff] = tcBottom;
							array[offset + offoff++] = tcBottom;
							lines.getFloatStore()[offoff] = red;
							array[offset + offoff++] = red;
							lines.getFloatStore()[offoff] = green;
							array[offset + offoff++] = green;
							lines.getFloatStore()[offoff] = blue;
							array[offset + offoff++] = blue;
							lines.getFloatStore()[offoff] = alpha;
							array[offset + offoff++] = alpha;

							lines.getFloatStore()[offoff] = left + charX;
							array[offset + offoff++] = left + charX;
							lines.getFloatStore()[offoff] = bottom + charY;
							array[offset + offoff++] = bottom + charY;
							lines.getFloatStore()[offoff] = tcLeft;
							array[offset + offoff++] = tcLeft;
							lines.getFloatStore()[offoff] = tcBottom;
							array[offset + offoff++] = tcBottom;
							lines.getFloatStore()[offoff] = red;
							array[offset + offoff++] = red;
							lines.getFloatStore()[offoff] = green;
							array[offset + offoff++] = green;
							lines.getFloatStore()[offoff] = blue;
							array[offset + offoff++] = blue;
							lines.getFloatStore()[offoff] = alpha;
							array[offset + offoff++] = alpha;
						}
					}
				}
			}
			if (lines.isDebug()) {
				/*
				 * for (int i = 0; i < lines.getFloatStoreNumber(); i++) {
				 * System.out.print("left-top position: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("left-top texcoords: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(", ");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("left-top rgba: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("right-top position: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("right-top texcoords: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(", ");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("right-top rgba: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("right-bottom position: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("right-bottom texcoords: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(", ");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("right-bottom rgba: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("left-bottom position: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("left-bottom texcoords: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i++]);
				 * System.out.print("left-bottom rgba: ");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.print(lines.getFloatStore()[i++]);
				 * System.out.print(",");
				 * System.out.println(lines.getFloatStore()[i]); }
				 */

			}
		}
	}
	private int convertIndividualSprite(final SpriteBase group,
			final float[] array, final int offset, final int off2,
			final float left, final float right, final float top,
			final float bottom, final float tcLeft, final float tcRight,
			final float tcTop, final float tcBottom, final float red,
			final float green, final float blue, final float alpha) {
		int offoff = off2;
		group.getFloatStore()[offoff] = left;
		array[offset + offoff++] = left;
		group.getFloatStore()[offoff] = top;
		array[offset + offoff++] = top;
		group.getFloatStore()[offoff] = tcLeft;
		array[offset + offoff++] = tcLeft;
		group.getFloatStore()[offoff] = tcTop;
		array[offset + offoff++] = tcTop;
		group.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		group.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		group.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		group.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		group.getFloatStore()[offoff] = right;
		array[offset + offoff++] = right;
		group.getFloatStore()[offoff] = top;
		array[offset + offoff++] = top;
		group.getFloatStore()[offoff] = tcRight;
		array[offset + offoff++] = tcRight;
		group.getFloatStore()[offoff] = tcTop;
		array[offset + offoff++] = tcTop;
		group.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		group.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		group.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		group.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		group.getFloatStore()[offoff] = right;
		array[offset + offoff++] = right;
		group.getFloatStore()[offoff] = bottom;
		array[offset + offoff++] = bottom;
		group.getFloatStore()[offoff] = tcRight;
		array[offset + offoff++] = tcRight;
		group.getFloatStore()[offoff] = tcBottom;
		array[offset + offoff++] = tcBottom;
		group.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		group.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		group.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		group.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;

		group.getFloatStore()[offoff] = left;
		array[offset + offoff++] = left;
		group.getFloatStore()[offoff] = bottom;
		array[offset + offoff++] = bottom;
		group.getFloatStore()[offoff] = tcLeft;
		array[offset + offoff++] = tcLeft;
		group.getFloatStore()[offoff] = tcBottom;
		array[offset + offoff++] = tcBottom;
		group.getFloatStore()[offoff] = red;
		array[offset + offoff++] = red;
		group.getFloatStore()[offoff] = green;
		array[offset + offoff++] = green;
		group.getFloatStore()[offoff] = blue;
		array[offset + offoff++] = blue;
		group.getFloatStore()[offoff] = alpha;
		array[offset + offoff++] = alpha;
		return offoff;
	}
	private void convertScrollingGroupOfTextToTexturedQuadDuringRender(
			final GroupOfText lines, final float[] array, final int offset)
			throws Exception {
		SimpleScrollingTextWindow parent =
				(SimpleScrollingTextWindow) GuiComponentLibrary.getInstance()
						.getComponent(lines.getParentRefId());
		if (parent.isDebug()) {
			System.out.println(parent.getClass().getCanonicalName()
					+ ".convertScrollingGroupOfTextToTexturedQuadDuringRender");
		}
		// float top = lines.getFullYb() + lines.getFullHeight();
		float left = lines.getFullXl();
		// float right = lines.getFullXl() + lines.getFullWidth();
		float bottom = lines.getFullYb();
		float red = lines.getFullRed(), green = lines.getFullGreen();
		float blue = lines.getFullBlue(), alpha = lines.getFullAlpha();
		FontsheetObject font = GameFont.getInstance().getFontById(
				lines.getFontRefId());
		int offoff = 0;
		int totalChar = 0;
		int lastLine = 0, firstLine = 0;
		lastLine = (parent).getCurrentLine();
		firstLine = lastLine;
		firstLine -=
				(parent).getNumLinesDisplayed();
		firstLine++;
		if (firstLine < 0) {
			firstLine = 0;
		}
		for (int i = lastLine; i >= firstLine; i--) {
			totalChar += lines.getLine(i).getNumberOfCharacters()
					* GlobalConsts.INT_032;
		}
		lines.setFloatStoreNumber(totalChar);
		if (parent.isDebug()) {

		}

		for (int curLine = lastLine; curLine >= firstLine; curLine--) {
			LineOfText line = lines.getLine(curLine);
			for (int curChar = 0; curChar < LineOfText.MAX_CHARS; curChar++) {
				if (line.getCharFrequency(curChar) > 0) {
					font.setGlyph((char) (curChar + GlobalConsts.INT_032));
					float right = left + font.getCharWidth();
					float top = bottom + font.getCharHeight();
					float tcLeft = font.getLeft(), tcRight = font.getRight();
					float tcBottom = font.getBottom(), tcTop = font.getTop();
					for (int i = 0; i < line.getCharFrequency(curChar); i++) {
						float charY = line.getYPosition();
						float charX = line.getXPosition(curChar, i);
						lines.getFloatStore()[offoff] = left + charX;
						array[offset + offoff++] = left + charX;
						lines.getFloatStore()[offoff] = top + charY;
						array[offset + offoff++] = top + charY;
						lines.getFloatStore()[offoff] = tcLeft;
						array[offset + offoff++] = tcLeft;
						lines.getFloatStore()[offoff] = tcTop;
						array[offset + offoff++] = tcTop;
						lines.getFloatStore()[offoff] = red;
						array[offset + offoff++] = red;
						lines.getFloatStore()[offoff] = green;
						array[offset + offoff++] = green;
						lines.getFloatStore()[offoff] = blue;
						array[offset + offoff++] = blue;
						lines.getFloatStore()[offoff] = alpha;
						array[offset + offoff++] = alpha;

						lines.getFloatStore()[offoff] = right + charX;
						array[offset + offoff++] = right + charX;
						lines.getFloatStore()[offoff] = top + charY;
						array[offset + offoff++] = top + charY;
						lines.getFloatStore()[offoff] = tcRight;
						array[offset + offoff++] = tcRight;
						lines.getFloatStore()[offoff] = tcTop;
						array[offset + offoff++] = tcTop;
						lines.getFloatStore()[offoff] = red;
						array[offset + offoff++] = red;
						lines.getFloatStore()[offoff] = green;
						array[offset + offoff++] = green;
						lines.getFloatStore()[offoff] = blue;
						array[offset + offoff++] = blue;
						lines.getFloatStore()[offoff] = alpha;
						array[offset + offoff++] = alpha;

						lines.getFloatStore()[offoff] = right + charX;
						array[offset + offoff++] = right + charX;
						lines.getFloatStore()[offoff] = bottom + charY;
						array[offset + offoff++] = bottom + charY;
						lines.getFloatStore()[offoff] = tcRight;
						array[offset + offoff++] = tcRight;
						lines.getFloatStore()[offoff] = tcBottom;
						array[offset + offoff++] = tcBottom;
						lines.getFloatStore()[offoff] = red;
						array[offset + offoff++] = red;
						lines.getFloatStore()[offoff] = green;
						array[offset + offoff++] = green;
						lines.getFloatStore()[offoff] = blue;
						array[offset + offoff++] = blue;
						lines.getFloatStore()[offoff] = alpha;
						array[offset + offoff++] = alpha;

						lines.getFloatStore()[offoff] = left + charX;
						array[offset + offoff++] = left + charX;
						lines.getFloatStore()[offoff] = bottom + charY;
						array[offset + offoff++] = bottom + charY;
						lines.getFloatStore()[offoff] = tcLeft;
						array[offset + offoff++] = tcLeft;
						lines.getFloatStore()[offoff] = tcBottom;
						array[offset + offoff++] = tcBottom;
						lines.getFloatStore()[offoff] = red;
						array[offset + offoff++] = red;
						lines.getFloatStore()[offoff] = green;
						array[offset + offoff++] = green;
						lines.getFloatStore()[offoff] = blue;
						array[offset + offoff++] = blue;
						lines.getFloatStore()[offoff] = alpha;
						array[offset + offoff++] = alpha;
					}
				}
			}
		}
		if (false) {
			// if (parent.isDebug()) {
			for (int i = 0; i < lines.getFloatStoreNumber(); i++) {
				System.out.print("left-top position: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("left-top texcoords: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(", ");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("left-top rgba: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("right-top position: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("right-top texcoords: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(", ");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("right-top rgba: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("right-bottom position: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("right-bottom texcoords: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(", ");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("right-bottom rgba: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("left-bottom position: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("left-bottom texcoords: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i++]);
				System.out.print("left-bottom rgba: ");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.print(lines.getFloatStore()[i++]);
				System.out.print(",");
				System.out.println(lines.getFloatStore()[i]);
			}
		}
	}
	/**
	 * Converts a {@link SpriteTileMap} instance into a list of floating-point
	 * variables that define its position and color.
	 * @param map the {@link SpriteTileMap}
	 * @param array the float array list to populate
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertSpriteTileMapToTexturedQuad(final SpriteTileMap map,
			final float[] array, final int offset) throws Exception {
		computeFullStats(map);
		int offoff = 0;
		map.setFloatStoreNumber(
				map.getNumberOfImagesVisible() * GlobalConsts.INT_032);
		final float x = map.getFullXl(), y = map.getFullYb();
		// go through every animated image
		for (int i = 0; i < map.getNumberOfAnimatedImages(); i++) {
			BasicSpriteObject tile = map.getAnimatedImage(i);
			SpriteImageObject image = SpriteImageObjectFactory.getInstance()
					.getImageById(tile.getImageRefId());
			Rectangle viewingRect = new Rectangle(map.getViewX(),
					map.getViewY(),
					map.getViewWidth(), map.getViewHeight()), tileRect = new Rectangle(
					(int) tile.getFullXl(), (int) tile.getFullYb(),
							tile.getFullWidth(), tile.getFullHeight());
			if (viewingRect.intersects(tileRect)) {
				float left = 0, right = 0, top = 0, bottom = 0, tcLeft = 0, tcRight = 0, tcTop = 0, tcBottom = 0;
				float red = tile.getFullRed(), green = tile.getFullGreen(), blue = tile
						.getFullBlue(), alpha = tile.getFullAlpha();
				if (viewingRect.contains(tileRect)) {
					// tile is displayed fully
					top = y + tile.getFullYb()
							+ tile.getFullHeight() - map.getViewY();
					left = x + tile.getFullXl() - map.getViewX();
					right = x + tile.getFullXl()
							+ tile.getFullWidth() - map.getViewX();
					bottom = y + tile.getFullYb() - map.getViewY();
					tcTop = image.getTop();
					tcLeft = image.getLeft();
					tcBottom = image.getBottom();
					tcRight = image.getRight();
				} else {
					// tile is displayed partially
					// calculate top, left, right, bottom
					// LEFT
					if (viewingRect.x <= tileRect.x) {
						// tile's left edge is inside viewing rectangle
						// left edge set at tile's left coordinate plus
						// the map's left coordinate, less the viewing offset
						left = tileRect.x + map.getFullXl() - viewingRect.x;
						tcLeft = image.getLeft();
					} else {
						// tile's left edge is outside viewing rectangle
						// left edge set at map's left coordinate
						left = map.getFullXl();
						// re-calculate the left edge
						tcLeft = image.getLeft();
						float diff = viewingRect.x - tileRect.x;
						tcLeft += diff / image.getParentWidth();
					}
					// RIGHT
					if (viewingRect.getMaxX() >= tileRect.getMaxX()) {
						// tile's right edge is inside viewing rectangle
						right = (float) tileRect.getMaxX()
								+ map.getFullXl() - viewingRect.x;
						tcRight = image.getRight();
					} else {
						// tile's right edge is outside viewing rectangle
						right = map.getFullXl() + map.getViewWidth();
						// re-calculate the left edge
						tcRight = image.getRight();
						float diff =
								(float) (tileRect.getMaxX() - viewingRect
										.getMaxX());
						tcRight -= diff / image.getParentWidth();
					}
					// TOP
					if (viewingRect.getMaxY() >= tileRect.getMaxY()) {
						// tile's top edge is inside viewing rectangle
						// top edge set at tile's top coordinate plus
						// the map's bottom coordinate, less the viewing offset
						top = (float) tileRect.getMaxY()
								+ map.getFullYb() - viewingRect.y;
						tcTop = image.getTop();
					} else {
						// tile's top edge is outside viewing rectangle
						// top edge set at map's top coordinate
						top = map.getFullYb() + map.getViewHeight();
						// re-calculate the top edge
						tcTop = image.getTop();
						float diff =
								(float) (tileRect.getMaxY() - viewingRect
										.getMaxY());
						tcTop += diff / image.getParentHeight();
					}
					// BOTTOM
					if (viewingRect.y <= tileRect.y) {
						// tile's bottom edge is inside viewing rectangle
						// bottom edge set at tile's bottom coordinate plus
						// the map's bottom coordinate, less the viewing offset
						bottom = tileRect.y
								+ map.getFullYb() - viewingRect.y;
						tcBottom = image.getBottom();
					} else {
						// tile's bottom edge is outside viewing rectangle
						// bottom edge set at map's bottom coordinate
						bottom = map.getFullYb();
						// re-calculate the bottom edge
						tcBottom = image.getBottom();
						float diff = viewingRect.y - tileRect.y;
						tcBottom -= diff / image.getParentHeight();
					}
				}
				offoff = convertIndividualSprite(
						map, array, offset, offoff,
						left, right, top, bottom,
						tcLeft, tcRight, tcTop, tcBottom,
						red, green, blue, alpha
						);
			}
		} // end for
			// go through every still image
		for (int i = 0; i < map.getNumberOfImages(); i++) {
			BasicSpriteObject tile = map.getImage(i);
			SpriteImageObject image = SpriteImageObjectFactory.getInstance()
					.getImageById(tile.getImageRefId());
			Rectangle viewingRect = new Rectangle(map.getViewX(),
					map.getViewY(),
					map.getViewWidth(), map.getViewHeight()), tileRect = new Rectangle(
					(int) tile.getFullXl(), (int) tile.getFullYb(),
							tile.getFullWidth(), tile.getFullHeight());
			if (viewingRect.intersects(tileRect)) {
				float left = 0, right = 0, top = 0, bottom = 0, tcLeft = 0, tcRight = 0, tcTop = 0, tcBottom = 0;
				float red = tile.getFullRed(), green = tile.getFullGreen(), blue = tile
						.getFullBlue(), alpha = tile.getFullAlpha();
				if (viewingRect.contains(tileRect)) {
					// tile is displayed fully
					top = y + tile.getFullYb()
							+ tile.getFullHeight() - map.getViewY();
					left = x + tile.getFullXl() - map.getViewX();
					right = x + tile.getFullXl()
							+ tile.getFullWidth() - map.getViewX();
					bottom = y + tile.getFullYb() - map.getViewY();
					tcTop = image.getTop();
					tcLeft = image.getLeft();
					tcBottom = image.getBottom();
					tcRight = image.getRight();
				} else {
					// tile is displayed partially
					// calculate top, left, right, bottom
					// LEFT
					if (viewingRect.x <= tileRect.x) {
						// tile's left edge is inside viewing rectangle
						// left edge set at tile's left coordinate plus
						// the map's left coordinate, less the viewing offset
						left = tileRect.x + map.getFullXl() - viewingRect.x;
						tcLeft = image.getLeft();
					} else {
						// tile's left edge is outside viewing rectangle
						// left edge set at map's left coordinate
						left = map.getFullXl();
						// re-calculate the left edge
						tcLeft = image.getLeft();
						float diff = viewingRect.x - tileRect.x;
						tcLeft += diff / image.getParentWidth();
					}
					// RIGHT
					if (viewingRect.getMaxX() >= tileRect.getMaxX()) {
						// tile's right edge is inside viewing rectangle
						right = (float) tileRect.getMaxX()
								+ map.getFullXl() - viewingRect.x;
						tcRight = image.getRight();
					} else {
						// tile's right edge is outside viewing rectangle
						right = map.getFullXl() + map.getViewWidth();
						// re-calculate the left edge
						tcRight = image.getRight();
						float diff =
								(float) (tileRect.getMaxX() - viewingRect
										.getMaxX());
						tcRight -= diff / image.getParentWidth();
					}
					// TOP
					if (viewingRect.getMaxY() >= tileRect.getMaxY()) {
						// tile's top edge is inside viewing rectangle
						// top edge set at tile's top coordinate plus
						// the map's bottom coordinate, less the viewing offset
						top = (float) tileRect.getMaxY()
								+ map.getFullYb() - viewingRect.y;
						tcTop = image.getTop();
					} else {
						// tile's top edge is outside viewing rectangle
						// top edge set at map's top coordinate
						top = map.getFullYb() + map.getViewHeight();
						// re-calculate the top edge
						tcTop = image.getTop();
						float diff =
								(float) (tileRect.getMaxY() - viewingRect
										.getMaxY());
						tcTop += diff / image.getParentHeight();
					}
					// BOTTOM
					if (viewingRect.y <= tileRect.y) {
						// tile's bottom edge is inside viewing rectangle
						// bottom edge set at tile's bottom coordinate plus
						// the map's bottom coordinate, less the viewing offset
						bottom = tileRect.y
								+ map.getFullYb() - viewingRect.y;
						tcBottom = image.getBottom();
					} else {
						// tile's bottom edge is outside viewing rectangle
						// bottom edge set at map's bottom coordinate
						bottom = map.getFullYb();
						// re-calculate the bottom edge
						tcBottom = image.getBottom();
						float diff = viewingRect.y - tileRect.y;
						tcBottom -= diff / image.getParentHeight();
					}
				}
				offoff = convertIndividualSprite(
						map, array, offset, offoff,
						left, right, top, bottom,
						tcLeft, tcRight, tcTop, tcBottom,
						red, green, blue, alpha
						);
			}
		} // end for
	}
	/**
	 * Converts a {@link SpriteBase} instance into a list of floating-point
	 * variables that define its position and color.
	 * @param sprite the {@link SpriteBase}
	 * @param array the float array list to populate
	 * @param offset the array offset
	 * @throws Exception if an error occurs
	 */
	public void convertSpriteToQuad(final SpriteBase sprite,
			final float[] array, final int offset) throws Exception {
		computeFullStats(sprite);
		float top = sprite.getFullYb() + sprite.getFullHeight();
		float left = sprite.getFullXl();
		float right = sprite.getFullXl() + sprite.getFullWidth();
		float bottom = sprite.getFullYb();
		float red = sprite.getFullRed(), green = sprite.getFullGreen();
		float blue = sprite.getFullBlue(), alpha = sprite.getFullAlpha();
		int offoff = 0;
		array[offset + offoff++] = left;
		array[offset + offoff++] = top;
		array[offset + offoff++] = red;
		array[offset + offoff++] = green;
		array[offset + offoff++] = blue;
		array[offset + offoff++] = alpha;

		array[offset + offoff++] = right;
		array[offset + offoff++] = top;
		array[offset + offoff++] = red;
		array[offset + offoff++] = green;
		array[offset + offoff++] = blue;
		array[offset + offoff++] = alpha;

		array[offset + offoff++] = right;
		array[offset + offoff++] = bottom;
		array[offset + offoff++] = red;
		array[offset + offoff++] = green;
		array[offset + offoff++] = blue;
		array[offset + offoff++] = alpha;

		array[offset + offoff++] = left;
		array[offset + offoff++] = bottom;
		array[offset + offoff++] = red;
		array[offset + offoff++] = green;
		array[offset + offoff++] = blue;
		array[offset + offoff++] = alpha;
	}
	public float[] getCoordinates(final SpriteBase sprite) {
		float[] coords = null;
		switch (sprite.getType()) {
		case SpriteBase.TYPE_00_BASIC_IMAGE:
		case SpriteBase.TYPE_06_QUADS:
		case SpriteBase.TYPE_10_PARTICLE:
			coords = new float[8];
			coords[0] = (float) sprite.getPosition().getX(); // left
			coords[1] = (float) sprite.getPosition().getY()
					+ sprite.getHeight(); // top
			coords[0] = (float) sprite.getPosition().getX() + sprite.getWidth(); // right
			coords[1] = (float) sprite.getPosition().getY()
					+ sprite.getHeight(); // top
			coords[0] = (float) sprite.getPosition().getX() + sprite.getWidth(); // right
			coords[0] = (float) sprite.getPosition().getY(); // bottom
			coords[0] = (float) sprite.getPosition().getX(); // left
			coords[0] = (float) sprite.getPosition().getY(); // bottom
			break;
		}
		return coords;
	}
	/**
	 * Gets the texture id associated with a specific sprite.
	 * @param sprite the {@link SpriteBase} instance
	 * @return int
	 */
	public int getTextureId(final SpriteBase sprite) {
		int id = -9999;
		try {
			if (sprite.getType() == SpriteBase.TYPE_00_BASIC_IMAGE
					|| sprite.getType() == SpriteBase.TYPE_01_GROUP_IMAGE
					|| sprite.getType() == SpriteBase.TYPE_09_TILE_MAP
					|| sprite.getType() == SpriteBase.TYPE_10_PARTICLE) {
				id = SpriteImageObjectFactory.getInstance()
						.getImageById(sprite.getImageRefId()).getTextureId();
			} else if (sprite.getType() == SpriteBase.TYPE_03_GROUP_TEXT) {
				id = GameFont.getInstance()
						.getFontById(((GroupOfText) sprite).getFontRefId())
						.getTextureId();
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		return id;
	}
	/**
	 * Determines whether or not this <code>Rectangle</code> and the specified
	 * <code>Rectangle</code> intersect. Two rectangles intersect if their
	 * intersection is nonempty.
	 * @param r the specified <code>Rectangle</code>
	 * @return <code>true</code> if the specified <code>Rectangle</code> and
	 *         this <code>Rectangle</code> intersect; <code>false</code>
	 *         otherwise.
	 */
	public boolean intersects(int X, int Y, int W, int H, int x2, int y2,
			int w2,
			int h2) {
		int tw = w2;
		int th = h2;
		int rw = W;
		int rh = H;
		if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
			return false;
		}
		int tx = x2;
		int ty = y2;
		int rx = X;
		int ry = Y;
		rw += rx;
		rh += ry;
		tw += tx;
		th += ty;
		// overflow || intersect
		return (rw < rx || rw > tx) &&
				(rh < ry || rh > ty) &&
				(tw < tx || tw > rx) &&
				(th < ty || th > ry);
	}
	/**
	 * Moves a sprite based on its velocity.
	 * @param sprite the sprite
	 */
	public void moveSprite(final SpriteBase sprite) {
		if (sprite.getMoveDuration() > 0) {
			long now = Time.getInstance().getFrameStart();
			if (now > sprite.getMoveStart() + sprite.getMoveDuration()) {
				// reset move timer
				sprite.setMoveStart(now);
				// move sprite by velocity amount
				System.out.println("b4m1::"+sprite.getPosition());
				sprite.getPosition().setX(sprite.getPosition().getX()
						+ sprite.getVelocity().getX());
				sprite.getPosition().setY(sprite.getPosition().getY()
						+ sprite.getVelocity().getY());
				System.out.println("afm1::"+sprite.getPosition());
			}
		} else {
			// no movement timer- -update at cpu clock speed
			System.out.println("b4m2::"+sprite.getPosition());
			sprite.getPosition().setX(sprite.getPosition().getX()
					+ sprite.getVelocity().getX());
			sprite.getPosition().setY(sprite.getPosition().getY()
					+ sprite.getVelocity().getY());
			System.out.println("afm2::"+sprite.getPosition());
		}
		sprite.clearFloatStore();
	}
	/**
	 * Scales a sprite.
	 * @param sprite the sprite instance
	 * @param factor the factor by which the sprite is scaled
	 */
	public void scaleSprite(final SpriteBase sprite, final float w, final float h) {
		sprite.setScaleFactorWidth(w);
		sprite.setScaleFactorHeight(h);
		sprite.assignFlag(SpriteBase.FLAG_SPRITE_SIZE_CHANGED);
	}
	/**
	 * Sets a sprite to be possibly partially rendered.
	 * @param sprite the sprite
	 * @param args the list of coordinates checked to see if partial rendering
	 *        is needed. They are as follows:<br/>
	 *        the sprite's top y-coordinate, <br/>
	 *        sprite's left x-coordinate,<br/>
	 *        sprite's bottom y-coordinate, <br/>
	 *        sprite's right x-coordinate,<br/>
	 *        the viewing area's top y-coordinate,<br/>
	 *        viewing area's left x-coordinate,<br/>
	 *        viewing area's bottom y-coordinate,<br/>
	 *        viewing area's right x-coordinate.
	 * @throws Exception if an error occurs
	 */
	public void setPartiallyRendered(final SpriteBase sprite,
			final double... args) throws Exception {
		if (args.length != GlobalConsts.INT_008) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Invalid number of parameters supplied!  Must have 8 ");
			sb.append("parameters in the following order: sprite's top ");
			sb.append("y-coordinate, sprite's left x-coordinate, sprite's ");
			sb.append("bottom y-coordinate, sprite's right x-coordinate, the ");
			sb.append("viewing area's top y-coordinate, viewing area's left ");
			sb.append("x-coordinate, viewing area's bottom y-coordinate, ");
			sb.append("viewing area's right x-coordinate.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		final double spriteTopY = args[0];
		final double spriteLeftX = args[1];
		final double spriteBottomY = args[2];
		final double spriteRightX = args[GlobalConsts.INT_003];
		final double maxY = args[GlobalConsts.INT_004];
		final double minX = args[GlobalConsts.INT_005];
		final double minY = args[GlobalConsts.INT_006];
		final double maxX = args[GlobalConsts.INT_007];
		if (spriteTopY > maxY
				|| minX > spriteLeftX
				|| minY > spriteBottomY
				|| spriteRightX > maxX) {
			// set flag for partial render
			sprite.assignFlag(SpriteBase.FLAG_SPRITE_RENDERED_PARTIALLY);
			int modWidth = 0, modHeight = 0;
			float modxl = 0f, modyb = 0f;
			float modtt = 0f, modtl = 0f, modtb = 0f, modtr = 0f;
			float scalex = 1f, scaley = 1f;
			if (sprite.hasFlag(SpriteBase.FLAG_SPRITE_SIZE_CHANGED)) {
				scalex = sprite.getScaleFactorWidth();
				scaley = sprite.getScaleFactorHeight();
			}
			if (spriteTopY > maxY) {
				modtt = (float) (spriteTopY - maxY) / scaley;
				modHeight -= (int) (spriteTopY - maxY);
			}
			if (minX > spriteLeftX) {
				modtl = (float) (minX - spriteLeftX) / scalex;
				modWidth -= (int) (minX - spriteLeftX);
				modxl = (float) (minX - spriteLeftX);
			}
			if (minY > spriteBottomY) {
				modtb = (float) (minY - spriteBottomY) / scaley;
				modHeight -= (int) (minY - spriteBottomY);
				modyb = (float) (minY - spriteBottomY);
			}
			if (spriteRightX > maxX) {
				modtr = (float) (spriteRightX - maxX) / scalex;
				modWidth -= (int) (spriteRightX - maxX);
			}
			if (spriteTopY < minY // sprite's top is below viewing area
					|| spriteLeftX > maxX // sprite's left is right of view
					|| spriteBottomY > maxY // sprite's bottom is above view
					|| spriteRightX < minX) { // sprite's right is left of view
				// hide a sprite that appears completely 
				// outside the viewing area
				modHeight = -GlobalConsts.INT_999;
				modWidth = -GlobalConsts.INT_999;
			}
			sprite.setModXl(modxl);
			sprite.setModWidth(modWidth);
			sprite.setModYb(modyb);
			sprite.setModHeight(modHeight);
			sprite.setModTCTop(modtt);
			sprite.setModTCLeft(modtl);
			sprite.setModTCBottom(modtb);
			sprite.setModTCRight(modtr);
		} else {
			sprite.setModXl(0);
			sprite.setModYb(0);
			sprite.setModWidth(0);
			sprite.setModHeight(0);
			sprite.setModTCTop(0);
			sprite.setModTCLeft(0);
			sprite.setModTCBottom(0);
			sprite.setModTCRight(0);
			// sprite displays fully
			sprite.removeFlag(SpriteBase.FLAG_SPRITE_RENDERED_PARTIALLY);
		}
	}
}
